home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 2001 May / macformat_103_may_2001.iso / Mac OS X Shareware / Fizilla / Chrome / toolkit.jar / content / global / filepicker.js < prev    next >
Encoding:
Text File  |  2001-03-26  |  13.4 KB  |  470 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * The Original Code is mozilla.org code.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape Communications
  16.  * Corporation.  Portions created by Netscape are
  17.  * Copyright (C) 2000 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  * Contributor(s): 
  21.  *  Stuart Parmenter <pavlov@netscape.com>
  22.  *  Brian Ryner <bryner@netscape.com>
  23.  *  Jan Varga <varga@utcru.sk>
  24.  *  Peter Annema <disttsc@bart.nl>
  25.  */
  26.  
  27. const nsILocalFile        = Components.interfaces.nsILocalFile;
  28. const nsILocalFile_CONTRACTID = "@mozilla.org/file/local;1";
  29. const nsIFilePicker       = Components.interfaces.nsIFilePicker;
  30. const nsIDirectoryServiceProvider = Components.interfaces.nsIDirectoryServiceProvider;
  31. const nsIDirectoryServiceProvider_CONTRACTID = "@mozilla.org/file/directory_service;1";
  32. const nsStdURL_CONTRACTID     = "@mozilla.org/network/standard-url;1";
  33. const nsIFileURL          = Components.interfaces.nsIFileURL;
  34. const NC_NAMESPACE_URI = "http://home.netscape.com/NC-rdf#";
  35.  
  36. var sfile = Components.classes[nsILocalFile_CONTRACTID].createInstance(nsILocalFile);
  37. var retvals;
  38. var filePickerMode;
  39. var currentFilter;
  40. var dirHistory;
  41. var homeDir;
  42.  
  43. var directoryTree;
  44. var textInput;
  45. var okButton;
  46.  
  47. var gFilePickerBundle;
  48.  
  49. function onLoad() {
  50.   gFilePickerBundle = document.getElementById("bundle_filepicker");
  51.  
  52.   dirHistory = new Array();
  53.  
  54.   directoryTree = document.getElementById("directoryTree");
  55.   textInput = document.getElementById("textInput");
  56.   okButton = document.getElementById("ok");
  57.  
  58.   if (window.arguments) {
  59.     var o = window.arguments[0];
  60.     retvals = o.retvals; /* set this to a global var so we can set return values */
  61.     const title = o.title;
  62.     filePickerMode = o.mode;
  63.     if (o.displayDirectory) {
  64.       const directory = o.displayDirectory.unicodePath;
  65.     }
  66.     const initialText = o.defaultString;
  67.     const filterTitles = o.filters.titles;
  68.     const filterTypes = o.filters.types;
  69.     const numFilters = filterTitles.length;
  70.  
  71.     window.title = title;
  72.  
  73.     if (initialText) {
  74.       textInput.value = initialText;
  75.     }
  76.   }
  77.  
  78.   if ((filePickerMode == nsIFilePicker.modeOpen) ||
  79.       (filePickerMode == nsIFilePicker.modeSave)) {
  80.  
  81.     currentFilter = filterTypes[0];
  82.     applyFilter();
  83.  
  84.     /* build filter popup */
  85.     var filterPopup = document.createElement("menupopup");
  86.  
  87.     for (var i = 0; i < numFilters; i++) {
  88.       var menuItem = document.createElement("menuitem");
  89.       menuItem.setAttribute("label", filterTitles[i] + " (" + filterTypes[i] + ")");
  90.       menuItem.setAttribute("filters", filterTypes[i]);
  91.       filterPopup.appendChild(menuItem);
  92.     }
  93.  
  94.     var filterMenuList = document.getElementById("filterMenuList");
  95.     filterMenuList.appendChild(filterPopup);
  96.     if (numFilters > 0)
  97.       filterMenuList.selectedIndex = 0;
  98.     var filterBox = document.getElementById("filterBox");
  99.     filterBox.removeAttribute("hidden");
  100.   } else if (filePickerMode == nsIFilePicker.modeGetFolder) {
  101.      // This applies a special filter to only show directories
  102.      applyDirectoryFilter();
  103.   }
  104.  
  105.   try {
  106.     var buttonLabel;
  107.     switch (filePickerMode) {
  108.       case nsIFilePicker.modeOpen:
  109.         buttonLabel = gFilePickerBundle.getString("openButtonLabel");
  110.         break;
  111.       case nsIFilePicker.modeSave:
  112.         buttonLabel = gFilePickerBundle.getString("saveButtonLabel");
  113.         break;
  114.       case nsIFilePicker.modeGetFolder:
  115.         buttonLabel = gFilePickerBundle.getString("selectFolderButtonLabel");
  116.         break;
  117.     }
  118.  
  119.     if (buttonLabel) {
  120.       okButton.setAttribute("label", buttonLabel);
  121.     }
  122.   } catch (exception) {
  123.     // keep it set to "OK"
  124.   }
  125.  
  126.   // setup the dialogOverlay.xul button handlers
  127.   doSetOKCancel(onOK, onCancel);
  128.  
  129.   // get the home dir
  130.   var dirServiceProvider = Components.classes[nsIDirectoryServiceProvider_CONTRACTID]
  131.                                      .getService(nsIDirectoryServiceProvider);
  132.   var persistent = new Object();
  133.   homeDir = dirServiceProvider.getFile("Home", persistent);
  134.  
  135.   if (directory) {
  136.     sfile.initWithUnicodePath(directory);
  137.   }
  138.   if (!directory || !(sfile.exists() && sfile.isDirectory())) {
  139.     // Start in the user's home directory
  140.     sfile.initWithUnicodePath(homeDir.unicodePath);
  141.   }
  142.  
  143.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  144.  
  145.   gotoDirectory(sfile);
  146.   doEnabling();
  147.   textInput.focus();
  148. }
  149.  
  150. function onFilterChanged(target)
  151. {
  152.   var filterTypes = target.getAttribute("filters");
  153.   currentFilter = filterTypes;
  154.   applyFilter();
  155. }
  156.  
  157. function applyFilter()
  158. {
  159.   /* This is where we manipulate the DOM to create new <rule>s */
  160.   var splitFilters = currentFilter.split("; ");
  161.   var matchAllFiles = false;
  162.   var ruleNode;
  163.  
  164.   /* get just the extensions for each of the filters */
  165.   var extensions = new Array(splitFilters.length);
  166.   for (var j = 0; j < splitFilters.length; j++) {
  167.     var tmpStr = splitFilters[j];
  168.     if (tmpStr == "*") {
  169.       matchAllFiles = true;
  170.       break;
  171.     } else
  172.       extensions[j] = tmpStr.substring(1); /* chop off the '*' */
  173.   }
  174.  
  175.   /* delete all rules except the first one */
  176.   for (j = 1;; j++) {
  177.     ruleNode = document.getElementById("matchRule."+j);
  178.     if (ruleNode) {
  179.       ruleNode.parentNode.removeChild(ruleNode);
  180.     } else {
  181.       break;
  182.     }
  183.   }
  184.  
  185.   /* if we are matching all files, just clear the extension attribute
  186.      on the first match rule and we're done */
  187.   var rule0 = document.getElementById("matchRule.0");
  188.   if (matchAllFiles) {
  189.     rule0.removeAttributeNS(NC_NAMESPACE_URI, "extension");
  190.     directoryTree.builder.rebuild();
  191.     return;
  192.   }
  193.  
  194.   /* rule 0 is special */
  195.   rule0.setAttributeNS(NC_NAMESPACE_URI, "extension" , extensions[0]);
  196.  
  197.   /* iterate through the remaining extensions, creating new rules */
  198.   ruleNode = document.getElementById("fileFilter");
  199.  
  200.   for (var k=1; k < extensions.length; k++) {
  201.     var newRule = rule0.cloneNode(true);
  202.     newRule.setAttribute("id", "matchRule."+k);
  203.     newRule.setAttributeNS(NC_NAMESPACE_URI, "extension", extensions[k]);
  204.     ruleNode.appendChild(newRule);
  205.   }
  206.  
  207.   directoryTree.builder.rebuild();
  208. }
  209.  
  210. function onOK()
  211. {
  212.   var ret = nsIFilePicker.returnCancel;
  213.  
  214.   var isDir = false;
  215.   var isFile = false;
  216.  
  217.   var input = textInput.value;
  218.   if (input[0] == '~') // XXX XP?
  219.     input  = homeDir.unicodePath + input.substring(1);
  220.  
  221.   var file = sfile.clone().QueryInterface(nsILocalFile);
  222.   if (!file)
  223.     return false;
  224.  
  225.   /* XXX we need an XP way to test for an absolute path! */
  226.   if (input[0] == '/')   /* an absolute path was entered */
  227.     file.initWithUnicodePath(input);
  228.   else {
  229.     try {
  230.       file.appendRelativeUnicodePath(input);
  231.     } catch (e) {
  232.       dump("Can't append relative path '"+input+"':\n");
  233.       return false;
  234.     }
  235.   }
  236.  
  237.   if (!file.exists() && (filePickerMode != nsIFilePicker.modeSave)) {
  238.     return false;
  239.   }
  240.  
  241.   if (file.exists()) {
  242.     isDir = file.isDirectory();
  243.     isFile = file.isFile();
  244.   }
  245.  
  246.   switch(filePickerMode) {
  247.   case nsIFilePicker.modeOpen:
  248.     if (isFile) {
  249.       retvals.directory = file.parent.unicodePath;
  250.       ret = nsIFilePicker.returnOK;
  251.     } else if (isDir) {
  252.       if (!sfile.equals(file)) {
  253.         gotoDirectory(file);
  254.       }
  255.       textInput.value = "";
  256.       doEnabling();
  257.       ret = nsIFilePicker.returnCancel;
  258.     }
  259.     break;
  260.   case nsIFilePicker.modeSave:
  261.     if (isFile) { // can only be true if file.exists()
  262.       // we need to pop up a dialog asking if you want to save
  263.       var message = gFilePickerBundle.getFormattedString("confirmFileReplacing",
  264.                                                          [file.unicodePath]);
  265.       var rv = window.confirm(message);
  266.       if (rv) {
  267.         ret = nsIFilePicker.returnReplace;
  268.         retvals.directory = file.parent.unicodePath;
  269.       } else {
  270.         ret = nsIFilePicker.returnCancel;
  271.       }
  272.     } else if (isDir) {
  273.       if (!sfile.equals(file)) {
  274.         gotoDirectory(file);
  275.       }
  276.       textInput.value = "";
  277.       doEnabling();
  278.       ret = nsIFilePicker.returnCancel;
  279.     } else {
  280.       var parent = file.parent;
  281.       if (parent.exists() && parent.isDirectory()) {
  282.         ret = nsIFilePicker.returnOK;
  283.         retvals.directory = parent.unicodePath;
  284.       } else {
  285.         var oldParent = parent;
  286.         while (!parent.exists()) {
  287.           oldParent = parent;
  288.           parent = parent.parent;
  289.         }
  290.         var errorTitle = gFilePickerBundle.getFormattedString("errorSavingFileTitle",
  291.                                                               [file.unicodePath]);
  292.         var errorMessage;
  293.         if (parent.isFile()) {
  294.           errorMessage = gFilePickerBundle.getFormattedString("saveParentIsFileMessage",
  295.                                                               [parent.unicodePath, file.unicodePath]);
  296.         } else {
  297.           errorMessage = gFilePickerBundle.getFormattedString("saveParentDoesntExistMessage",
  298.                                                               [oldParent.unicodePath, file.unicodePath]);
  299.         }
  300.         var commonDialogs = Components.classes["@mozilla.org/appshell/commonDialogs;1"]
  301.                                       .getService(Components.interfaces.nsICommonDialogs);
  302.         commonDialogs.Alert(window, errorTitle, errorMessage);
  303.         ret = nsIFilePicker.returnCancel;
  304.       }
  305.     }
  306.     break;
  307.   case nsIFilePicker.modeGetFolder:
  308.     if (isDir) {
  309.       retvals.directory = file.parent.unicodePath;
  310.     } else { // if nothing selected, the current directory will be fine
  311.       retvals.directory = sfile.unicodePath;
  312.     }
  313.     ret = nsIFilePicker.returnOK;
  314.     break;
  315.   }
  316.  
  317.   retvals.file = file;
  318.   retvals.buttonStatus = ret;
  319.  
  320.   if (ret == nsIFilePicker.returnCancel)
  321.     return false;
  322.   else
  323.     return true;
  324. }
  325.  
  326. function onCancel()
  327. {
  328.   // Close the window.
  329.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  330.   retvals.file = null;
  331.   return true;
  332. }
  333.  
  334. function onClick(e) {
  335.   if ( e.detail == 2 ) {
  336.     var path = e.target.parentNode.getAttribute("path");
  337.  
  338.     if (path) {
  339.       var file = URLpathToFile(path);
  340.       if (file) {
  341.         if (file.isDirectory()) {
  342.           gotoDirectory(file);
  343.         }
  344.         else if (file.isFile()) {
  345.           doOKButton();
  346.         }
  347.       }
  348.     }
  349.   }
  350. }
  351.  
  352. function onKeypress(e) {
  353.   if (e.keyCode == 8) /* backspace */
  354.     goUp();
  355. }
  356.  
  357. function doEnabling() {
  358.   // Maybe add check if textInput.value would resolve to an existing
  359.   // file or directory in .modeOpen. Too costly I think.
  360.   var enable = (textInput.value != "");
  361.  
  362.   okButton.disabled = !enable;
  363. }
  364.  
  365. function onSelect(e) {
  366.   if (e.target.selectedItems.length != 1)
  367.     return;
  368.   var path = e.target.selectedItems[0].firstChild.getAttribute("path");
  369.  
  370.   if (path) {
  371.     var file = URLpathToFile(path);
  372.     if (file) {
  373.       /* Put the leafName of the selected item in the input field if:
  374.          - GetFolder mode   : a directory was selected (only option)
  375.          - Open or Save mode: a file was selected                    */
  376.       if ((filePickerMode == nsIFilePicker.modeGetFolder) || file.isFile()) {
  377.         textInput.value = file.unicodeLeafName;
  378.         doEnabling();
  379.       }
  380.     }
  381.   }
  382. }
  383.  
  384. function onDirectoryChanged(target)
  385. {
  386.   var path = target.getAttribute("label");
  387.  
  388.   var file = Components.classes[nsILocalFile_CONTRACTID].createInstance(nsILocalFile);
  389.   file.initWithUnicodePath(path);
  390.  
  391.   if (!sfile.equals(file)) {
  392.     gotoDirectory(file);
  393.   }
  394. }
  395.  
  396. function addToHistory(directoryName) {
  397.   var found = false;
  398.   var i = 0;
  399.   while (!found && i<dirHistory.length) {
  400.     if (dirHistory[i] == directoryName)
  401.       found = true;
  402.     else
  403.       i++;
  404.   }
  405.  
  406.   if (found) {
  407.     if (i!=0) {
  408.       dirHistory.splice(i, 1);
  409.       dirHistory.splice(0, 0, directoryName);
  410.     }
  411.   } else {
  412.     dirHistory.splice(0, 0, directoryName);
  413.   }
  414.  
  415.   var menu = document.getElementById("lookInMenu");
  416.  
  417.   var children = menu.childNodes;
  418.   for (i=0; i < children.length; i++)
  419.     menu.removeChild(children[i]);
  420.  
  421.   for (i=0; i < dirHistory.length; i++) {
  422.     var menuItem = document.createElement("menuitem");
  423.     menuItem.setAttribute("label", dirHistory[i]);
  424.     menu.appendChild(menuItem);
  425.   }
  426.  
  427.   var menuList = document.getElementById("lookInMenuList");
  428.   menuList.selectedIndex = 0;
  429. }
  430.  
  431. function goUp() {
  432.   try {
  433.     var parent = sfile.parent;
  434.   } catch(ex) { dump("can't get parent directory\n"); }
  435.  
  436.   if (parent) {
  437.     gotoDirectory(parent);
  438.   }
  439. }
  440.  
  441. function gotoDirectory(directory) {
  442.   addToHistory(directory.unicodePath);
  443.   directoryTree.setAttribute("ref", fileToURL(directory).spec);
  444.   sfile = directory;
  445. }
  446.  
  447. function fileToURL(aFile) {
  448.   var newDirectoryURL = Components.classes[nsStdURL_CONTRACTID].createInstance().QueryInterface(nsIFileURL);
  449.   newDirectoryURL.file = aFile;
  450.   return newDirectoryURL;
  451. }
  452.  
  453. function URLpathToFile(aURLstr) {
  454.   var fileURL = Components.classes[nsStdURL_CONTRACTID].createInstance().QueryInterface(nsIFileURL);
  455.   fileURL.spec = aURLstr;
  456.   return fileURL.file;
  457. }
  458.  
  459. function applyDirectoryFilter() {
  460.   var ruleNode = document.getElementById("matchRule.0");
  461.  
  462.   // A file can never have an extension of ".", because the extension is
  463.   // by definition everything after the last dot.  So, this rule will
  464.   // cause only directories to show up.
  465.   ruleNode.setAttributeNS(NC_NAMESPACE_URI, "extension", ".");
  466.  
  467.   directoryTree.builder.rebuild();
  468. }
  469.  
  470.